package org.gwt.pluginframework.common;

import org.gwt.pluginframework.common.event.CommonEvents;
import org.gwt.pluginframework.common.event.IPluginEvent;
import org.gwt.pluginframework.common.event.IPluginEventHandler;
import org.gwt.pluginframework.common.event.PluginEvent;
import org.gwt.pluginframework.common.extension.IExtension;

public abstract class Plugin implements IPlugin {
	private static final long serialVersionUID = 7142057617884978290L;

	// FIXME
	//  should it be extra class or embed those information in plug-in?
	protected PluginManifest manifest = new PluginManifest();

	protected IPluginManager manager;

	public Plugin() {
		// annotations would be better but they do not yet work as expected
		setupManifest();
	}

	public boolean isStarted() {
		if (manifest.state == PluginState.STARTED) {
			return true;
		}
		return false;
	}

	public String getName() {
		return manifest.getName();
	}

	public String getVersion() {
		return manifest.getVersion();
	}
	
	public boolean isManaged() {
		return manager != null;
	}

	public void setPluginManager(IPluginManager manager) {
		this.manager = manager;
	}

	public IPluginManager getPluginManager() {
		return manager;
	}

	public PluginManifest getManifest() {
		return manifest;
	}
	
	public void onInitialize() {
		// do nothing
	}

	public void onStart() {
		// do nothing
	}

	public void onStop() {
		// do nothing
	}

	public void onDestroy() {
		// do nothing
	}
	
	final public void initialize() {
		manifest.validate();

		long start = System.currentTimeMillis();
		onInitialize();
		
		manager.dispatch(new PluginEvent(
				CommonEvents.PLUGIN_INITIALIZED_EVENT, this,
				new String[] { "time" }, 
				new Object[] { System.currentTimeMillis() - start }));
		
		manifest.setState(PluginState.INITIALIZED);
	}

	final public void start() {
		long start = System.currentTimeMillis();
		onStart();
		
		manager.dispatch(new PluginEvent(CommonEvents.PLUGIN_STARTED_EVENT, this,
				new String[] { "time" }, 
				new Object[] { System.currentTimeMillis() - start }));
	
		manifest.setState(PluginState.STARTED);
	}

	final public void stop() {
		long start = System.currentTimeMillis();
		onStop();
		
		manager.dispatch(new PluginEvent(CommonEvents.PLUGIN_STOPPED_EVENT, this,
				new String[] { "time" }, 
				new Object[] { System.currentTimeMillis() - start }));
		
		manifest.setState(PluginState.STOPED);
	}

	final public void destroy() {
		final long start = System.currentTimeMillis();
		onDestroy();
		
		manager.dispatch(new PluginEvent(CommonEvents.PLUGIN_DESTROYED_EVENT, this,
				new String[] { "time" }, 
				new Object[] { System.currentTimeMillis() - start }));
		
		// FIXME 
		//  manifest can not be null because stop event handle will occur after destroy
//		manifest = null;
	}

	// FIXME 
	//  it should be topology sort
	public int compareTo(IPlugin o) {
		if (this instanceof IExtension) {
			return -1;
		} else {
			return 1;
		}
		// return 0;
	}
	
	protected void registerEventHandler(IPluginEventHandler handler) {
		manager.registerEventHandler(this, handler);
	}
	
	protected void dispatch(IPluginEvent event) {
		if(event instanceof PluginEvent) {
			((PluginEvent) event).setInvoker(this);
		}
		manager.dispatch(event);
	}
}
